package inner.anonymous;

public class AnonymousInnerClass {
    private int n = 10;

    void method() {
        Father fa = new Father("tom") {
            private int n = 666;
            //当匿名内部类 中的属性与外部类的属性 相同时 遵循就近原则

            @Override
            public void test() {//同其他内部类一样可通过 外部类类名.this.属性 来访问外部类中的属性或方法
                System.out.println("匿名内部类 AnonymousInnerClass.this=" + AnonymousInnerClass.this);
                System.out.println("匿名内部类中的n=" + n + " 外部类中的n=" + AnonymousInnerClass.this.n);
            }
        };
        fa.test();
    }

    public static void main(String[] args) {
        //当我们想要实现一个接口时就必须去写一个类
        //但有时我们就只想使用这个接口 不想很规范的去写一个完整的类
        //这时就可以使用匿名内部类 来减轻开发的复杂度

        //匿名内部类:
        //Java中的匿名内部类是一种特殊的内部类 它可以在声明的同时直接实例化
        //并且不需要显式地命名 所以被称为匿名内部类 它的语法通常形如:
        /*
        new 父类或接口名(){
            // 匿名类的具体实现
        }

        new 父类或接口名(构造方法参数列表){
            // 匿名类的具体实现
        }
         */

        //1.基于接口的匿名内部类:
        ICry dog = new ICry() {
            @Override
            public void cry() {
                System.out.println("狗在旺旺叫");
            }
        };
        dog.cry();//狗在旺旺叫
        //Dog 的编译类型是 ICry 运行类型却是匿名内部类 AnonymousInnerClass$1
        System.out.println(dog.getClass());//class inner.anonymous.AnonymousInnerClass$1
        //匿名内部类只能实例化一次 因为匿名内部类只在编译时进行一次定义
        //2.基于类的匿名内部类:
        //                  构造方法参数列表
        //Father fa = new Father("tom") {
        //};//调用了father 的构造方法 传入的name = tom

        AnonymousInnerClass Outer = new AnonymousInnerClass();
        System.out.println("外部类 hashcode=" + Outer);
        Outer.method();
        /*
         * 外部类 hashcode=inner.anonymous.AnonymousInnerClass@682a0b20
         * 调用了father 的构造方法 传入的name = tom
         * 匿名内部类 AnonymousInnerClass.this=inner.anonymous.AnonymousInnerClass@682a0b20
         * 匿名内部类中的n=666 外部类中的n=10
         */

        Animal duck = new Animal() {
            @Override
            public void eat() {
                System.out.println("鸭子在吃东西");
            }
        };
        duck.eat();//鸭子在吃东西
        /*
         * 匿名内部类的特点包括：
         *
         * 匿名内部类通常用于实现某个接口或者继承某个类，并且只使用一次。它不能是抽象类，必须要实现所有接口或抽象方法。
         *
         * 匿名内部类可以访问外部类的成员变量和方法(包括private)，但是外部类无法访问匿名内部类的成员变量和方法。
         *
         * 匿名内部类可以引用final修饰的局部变量，但是必须在编译时确定其值，而不能在运行时修改。
         *
         * 匿名内部类的作用域在声明的方法内，不能被外部方法访问。
         *
         * 由于它没有名字，因此无法在别的地方再次使用，一般只能在声明的时候进行实例化，因此使用最多的场合是事件处理和线程实现。
         */
    }
}

interface ICry {
    public void cry();
}

class Father {
    public Father(String name) {
        System.out.println("调用了father 的构造方法 传入的name = " + name);
    }

    public void test() {
        System.out.println("father::test");
    }
}

abstract class Animal {
    abstract public void eat();
}
